
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "esUtil.h"
#include "load_Shader.h"
#include "Matrix/matrix.h"

#define DEGREES_TO_RADIANS(x)	(3.14159265358979323846 * x / 180.0)
#define RANDOM_FLOAT_BETWEEN(x, y)	(((float) rand() / RAND_MAX) * (y - x) + x)
typedef struct
{
	// Handle to a program object
	GLuint programObject;

} UserData;

///
// Create a shader object, load the shader source, and
// compile the shader.
//
GLuint LoadShader ( GLenum type, const char *shaderSrc )
{
	GLuint shader;
	GLint compiled;

	// Create the shader object
	shader = glCreateShader ( type );

	if ( shader == 0 )
		return 0;

	// Load the shader source
	glShaderSource ( shader, 1, &shaderSrc, NULL );

	// Compile the shader
	glCompileShader ( shader );

	// Check the compile status
	glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled );

	if ( !compiled ) 
	{
		GLint infoLen = 0;

		glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen );

		if ( infoLen > 1 )
		{
			char* infoLog = (char*)malloc (sizeof(char) * infoLen );

			glGetShaderInfoLog ( shader, infoLen, NULL, infoLog );
			esLogMessage ( "Error compiling shader:\n%s\n", infoLog );            

			free ( infoLog );
		}

		glDeleteShader ( shader );
		return 0;
	}

	return shader;

}

///
// Initialize the shader and program object
//
int Init ( ESContext *esContext )
{
	UserData *userData = (UserData *)esContext->userData;
	char * vShaderStr = ReadFile("./shader/vshader.glsl");
	char * fShaderStr = ReadFile("./shader/fshader.glsl");

	GLuint vertexShader;
	GLuint fragmentShader;
	GLuint programObject;
	GLint linked;

	// Load the vertex/fragment shaders
	vertexShader = LoadShader ( GL_VERTEX_SHADER, (char*)vShaderStr );
	fragmentShader = LoadShader ( GL_FRAGMENT_SHADER, (char*)fShaderStr );

	// Create the program object
	programObject = glCreateProgram ( );

	if ( programObject == 0 )
		return 0;

	glAttachShader ( programObject, vertexShader );
	glAttachShader ( programObject, fragmentShader );


	// Bind vPosition to attribute 0   
	glBindAttribLocation ( programObject, 0, "vPosition" );
	
	// Link the program
	glLinkProgram ( programObject );

	// Check the link status
	glGetProgramiv ( programObject, GL_LINK_STATUS, &linked );

	if ( !linked ) 
	{
		GLint infoLen = 0;

		glGetProgramiv ( programObject, GL_INFO_LOG_LENGTH, &infoLen );

		if ( infoLen > 1 )
		{
			char* infoLog = (char*)malloc (sizeof(char) * infoLen );

			glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog );
			esLogMessage ( "Error linking program:\n%s\n", infoLog );            

			free ( infoLog );
		}

		glDeleteProgram ( programObject );
		return FALSE;
	}

	// Store the program object
	userData->programObject = programObject;

	glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );
	return TRUE;
}


Matrix m_maProjection;
///
// Draw a triangle using the shader pair created in Init()
//
void Draw ( ESContext *esContext )
{
	UserData *userData = (UserData *)esContext->userData;
	GLfloat vertices[360*3];
	for (int i = 0; i < 360*3; i += 3) {
		// x value
		vertices[i]   = (cos(DEGREES_TO_RADIANS(i)) * 1);
		// y value
		vertices[i+1] = (sin(DEGREES_TO_RADIANS(i)) * 1);
		// z value
		vertices[i+2] = 0.0f;
	}

	GLfloat vVertices[] = {  0.0f,  0.5f, 0.0f, 
		-0.5f, -0.5f, 0.0f,
		0.5f, -0.5f, 0.0f };

	// Set the viewport
	glViewport ( 0, 0, esContext->width, esContext->height );

	// Clear the color buffer
	glClear ( GL_COLOR_BUFFER_BIT );

	// Use the program object
	glUseProgram ( userData->programObject );

	m_maProjection.MakeIdentity();
	m_maProjection.SetPerspective(1.0f, -1.0f,-(esContext->width/esContext->height),(esContext->width/esContext->height),1.0f,-1.0f);

	//maMvpMatrix = m_maProjection;
	m_maProjection.MakeTranspose(); //transpose matrix

	float *fMvpMatrix = m_maProjection.ToArray(); // convert to 1 dimension array
	
	GLint mvpMatrixLoc = glGetUniformLocation(userData->programObject,"u_mvpMatrix");

	glUniformMatrix4fv(mvpMatrixLoc, 1, GL_FALSE, fMvpMatrix );
	// Load the vertex data
	glVertexAttribPointer ( 0, 3, GL_FLOAT, GL_FALSE, 0, vertices );
	glEnableVertexAttribArray ( 0 );

	glDrawArrays ( GL_TRIANGLE_FAN, 0, 360 );

	eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface );
}


int main ( int argc, char *argv[] )
{
	ESContext esContext;
	UserData  userData;

	esInitContext ( &esContext );
	esContext.userData = &userData;

	esCreateWindow ( &esContext, "Hello Circle", 800, 800, ES_WINDOW_RGB );


	if ( !Init ( &esContext ) )
		return 0;

	esRegisterDrawFunc ( &esContext, Draw );
	
	esMainLoop ( &esContext );

}
